package com.xbts.system.module.connect.util;

import cn.hutool.json.JSONUtil;
import com.xbts.common.core.domain.Setting;
import com.xbts.common.core.redis.RedisCache;
import com.xbts.common.enums.ClientTypeEnum;
import com.xbts.common.enums.SettingEnum;
import com.xbts.common.exception.ServiceException;
import com.xbts.system.module.connect.config.AuthConfig;
import com.xbts.system.module.connect.config.ConnectAuthEnum;
import com.xbts.system.module.connect.entity.dto.*;
import com.xbts.system.module.connect.exception.AuthException;
import com.xbts.system.module.connect.request.AuthRequest;
import com.xbts.system.module.connect.request.BaseAuthWeChatPCRequest;
import com.xbts.system.service.SettingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 联合登陆工具类
 *
 * @author Chopper
 * @version v1.0
 * 2020-11-25 21:16
 */
@Slf4j
@Component
public class ConnectUtil {

    @Autowired
    private RedisCache cache;

    @Autowired
    private SettingService settingService;

    @Value("${xbts.domain}")
    private String domain;

    static String prefixMember = "/system/connect/callback";

    /**
     * 回调地址获取
     * @param connectAuthEnum 用户枚举
     * @return 回调地址
     */
    String getRedirectUri(ConnectAuthEnum connectAuthEnum) {
        String urlPrefix = domain + prefixMember;
        return urlPrefix + connectAuthEnum.getName();
    }

    /**
     * 登录回调
     *
     * @param callback           回调参数
     * @param httpServletResponse 响应
     * @param httpServletRequest 请求
     */
    public void callback(AuthCallback callback, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        AuthRequest authRequest = this.getAuthRequest(ClientTypeEnum.PC.value());

        AuthResponse<ConnectAuthUser> response = authRequest.login(callback);
        //联合登陆处理，如果响应正常，则录入响应结果到redis
        ConnectAuthUser authUser = null;
        if (response.ok()) {
            authUser = response.getData();
            log.info("第三方登录登录用户信息：" + authUser);
        } else { //否则录入响应结果，等待前端获取信息
            log.error("第三方登录失败：第三方返回的返回信息为：{}", response.getMsg());
            throw new ServiceException(response.getMsg());
        }

        //跳转地址
        String url = this.check(httpServletRequest.getHeader("user-agent")) ?
                domain + "/pages/passport/loginLoad?state=" + callback.getCode() :
                domain + "/loginLoad?state=" + callback.getCode();
        url += "&unionId=" + authUser.getUuid();
        log.info("三方登录重定向地址：{}", url);
        try {
            httpServletResponse.sendRedirect(url);
        } catch (Exception e) {
            log.error("登录回调错误", e);
        }
    }

    /**
     * 联合登录
     * @param type 枚举
     * @return
     */
    public AuthRequest getAuthRequest(String type) {
        ConnectAuthEnum authInterface = ConnectAuthEnum.valueOf(type);
        log.debug("登录方式：{}",authInterface);
//        if (authInterface == null) {
//            throw new ServiceException(ResultCode.CONNECT_NOT_EXIST);
//        }
        AuthRequest authRequest = null;
        switch (authInterface) {
            case WECHAT_PC: {
                //寻找配置
                Setting setting = settingService.get(SettingEnum.WECHAT_CONNECT.name());
                WechatConnectSetting wechatConnectSetting = JSONUtil.toBean(setting.getSettingValue(), WechatConnectSetting.class);
                for (WechatConnectSettingItem wechatConnectSettingItem : wechatConnectSetting.getWechatConnectSettingItems()) {
                    if (wechatConnectSettingItem.getClientType().equals(ClientTypeEnum.PC.name())) {
                        authRequest = new BaseAuthWeChatPCRequest(AuthConfig.builder()
                                .clientId(wechatConnectSettingItem.getAppId())
                                .clientSecret(wechatConnectSettingItem.getAppSecret())
                                .redirectUri(getRedirectUri(authInterface))
                                .build(), cache);
                    }
                }
                break;
            }
            default:
                break;
        }
        if (null == authRequest) {
            throw new AuthException("暂不支持第三方登陆");
        }
        return authRequest;
    }

    /**
     * \b 是单词边界(连着的两个(字母字符 与 非字母字符) 之间的逻辑上的间隔),
     * 字符串在编译时会被转码一次,所以是 "\\b"
     * \B 是单词内部逻辑间隔(连着的两个字母字符之间的逻辑上的间隔)
     */
    static String phoneReg = "\\b(ip(hone|od)|android|opera m(ob|in)i"
            + "|windows (phone|ce)|blackberry"
            + "|s(ymbian|eries60|amsung)|p(laybook|alm|rofile/midp"
            + "|laystation portable)|nokia|fennec|htc[-_]"
            + "|mobile|up.browser|[1-4][0-9]{2}x[1-4][0-9]{2})\\b";
    static String tableReg = "\\b(ipad|tablet|(Nexus 7)|up.browser"
            + "|[1-4][0-9]{2}x[1-4][0-9]{2})\\b";

    /**
     * 移动设备正则匹配：手机端、平板
     */
    static Pattern phonePat = Pattern.compile(phoneReg, Pattern.CASE_INSENSITIVE);
    static Pattern tablePat = Pattern.compile(tableReg, Pattern.CASE_INSENSITIVE);

    /**
     * 检测是否是移动设备访问
     *
     * @param userAgent 浏览器标识
     * @return true:移动设备接入，false:pc端接入
     * @Title: check
     */
    private boolean check(String userAgent) {
        if (null == userAgent) {
            userAgent = "";
        }
        //匹配
        Matcher matcherPhone = phonePat.matcher(userAgent);
        Matcher matcherTable = tablePat.matcher(userAgent);
        if (matcherPhone.find() || matcherTable.find()) {
            return true;
        } else {
            return false;
        }
    }

}

